/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ru.niir.goodfil.ui;

import org.apache.log4j.Logger;
import ru.niir.goodfil.audit.domain.ClientUIEvent;
import ru.niir.goodfil.audit.domain.enums.Crud;
import ru.niir.goodfil.db.Client;
import ru.niir.goodfil.db.ClientGroup;
import ru.niir.goodfil.db.Role;
import ru.niir.goodfil.db.User;
import ru.niir.goodfil.db.dic.ClientState;
import ru.niir.goodfil.exceptions.RemoveFailureException;
import ru.niir.goodfil.ui.utils.PageIndex;
import ru.niir.goodfil.utils.Pair;

import javax.faces.model.SelectItem;
import java.util.ArrayList;
import java.util.List;

public class ClientsBean extends PageBean {
    private static Logger logger = Logger.getLogger(ClientsBean.class);

    /**
     * Название настройки, задающей размер страницы
     */
    private static final String CLIENTS_PAGE_SIZE_KEY = ".clients.page.size";
    /**
     * Название настройки, задающей отступ от текущей страницы влево для пэйджинатора
     */
    private static final String CLIENTS_LEFT_PAGE_OFFSET_SIZE = ".clients.page.left.offset";
    /**
     * Название настройки, задающей отступ от текущей страницы вправо для пэйджинатора
     */
    private static final String CLIENTS_RIGHT_PAGE_OFFSET_SIZE = ".clients.page.right.offset";

    /**
     * Количество страниц (с учетом фильтра)
     */
    private int pagesCount = -1;
    /**
     * Количество товаров (с учетом фильтра)
     */
    private int clientsCount = -1;
    /**
     * Размер страницы
     */
    private int pageSize = -1;
    /**
     * Отступ от текущей страницы влево для паджинатора (кол-во страниц, слева от текущей)
     */
    private int _leftPageOffset = -1;
    /**
     * Отступ от текущей страницы вправо для паджинатора (кол-во страниц, справа от текущей)
     */
    private int _rightPageOffset = -1;

    /**
     * Возвращает (согласно настройкам) размер страницы (для пэйджинатора)
     *
     * @return размер страницы
     */
    public int getPageSize() {
        gf().createIfNotExists(CLIENTS_PAGE_SIZE_KEY, 10);
        if (pageSize == -1) pageSize = gf().getInt(CLIENTS_PAGE_SIZE_KEY);
        return pageSize;
    }

    /**
     * Возвращает (согласно настройкам) размер отступа влево (в страницах) для пэйджинатора
     *
     * @return размер отступа
     */
    public int getLeftPaggeOffset() {
        gf().createIfNotExists(CLIENTS_LEFT_PAGE_OFFSET_SIZE, 5);
        if (_leftPageOffset == -1) _leftPageOffset = gf().getInt(CLIENTS_LEFT_PAGE_OFFSET_SIZE);
        return _leftPageOffset;
    }

    /**
     * Возвращает (согласно настройкам) размер отступа вправо (в страницах) для пэйджинатора
     *
     * @return размер отступа
     */
    public int getRightPaggeOffset() {
        gf().createIfNotExists(CLIENTS_RIGHT_PAGE_OFFSET_SIZE, 5);
        if (_rightPageOffset == -1) _rightPageOffset = gf().getInt(CLIENTS_RIGHT_PAGE_OFFSET_SIZE);
        return _rightPageOffset;
    }

    /**
     * Возвращает количество страниц (с учетом фильтра)
     *
     * @return количество страниц
     */
    public int getPagesCount() {
        if (pagesCount == -1) pagesCount = getClientsCount() / getPageSize() + 1;
        return pagesCount;
    }

    public int getClientsCount() {
        if (clientsCount == -1) clientsCount = (int) gf().getClientsCount(getSessionBean().getClientsFilter());
        return clientsCount;
    }

    public int getAllClientsCount() {
        return (int) gf().getClientsCount(null);
    }

    /**
     * Перейти к началу (на первую страницу)
     */
    public void toBegin() {
        applyPage();
        setPage(1);
    }

    /**
     * Перейти к концу (на последнюю страницу)
     */
    public void toEnd() {
        applyPage();
        setPage(getPagesCount());
    }

    /**
     * Отступить на несколько страниц назад
     */
    public void longPrevPage() {
        applyPage();
        int p = getPage() - getLeftPaggeOffset() - 1;
        if (p < 1) p = 1;
        setPage(p);
    }

    /**
     * Отступить на несколько страниц вперед
     */
    public void longNextPage() {
        applyPage();
        int p = getPage() + getRightPaggeOffset() + 1;
        if (p > getPagesCount()) p = getPagesCount();
        setPage(p);
    }

    /**
     * Перейти на страницу вперед
     */
    public void nextPage() {
        applyPage();
        if (getPage() < getPagesCount()) setPage(getPage() + 1);
    }

    /**
     * Перейти на страницу назад
     */
    public void prevPage() {
        applyPage();
        if (getPage() > 1) setPage(getPage() - 1);
    }

    /**
     * Возвращает номер текущей страницы
     *
     * @return номер страници
     */
    public int getPage() {
        return getSessionBean().getClientsPage();
    }

    /**
     * Устанавливает номер текущей страницы.
     *
     * @param page номер страници
     */
    public void setPage(int page) {
        getSessionBean().setClientsPage(page);
    }

    /**
     * Применить текущую страницу
     */
    public void applyPage() {
        clientsCount = -1;
        pagesCount = -1;
    }

    /**
     * Возвращает номера страниц для отрисовки в пэйджинаторе
     *
     * @return номера страниц
     */
    public List<PageIndex> getPageIndexes() {
        int minPage = getPage() - getLeftPaggeOffset();
        if (minPage < 1) minPage = 1;

        int maxPage = minPage + getLeftPaggeOffset() + getRightPaggeOffset();
        if (maxPage > getPagesCount()) maxPage = getPagesCount();

        List<PageIndex> result = new ArrayList<PageIndex>();
        for (int i = minPage; i <= maxPage; i++)
            result.add(new PageIndex(i, i == getPage()));

        return result;
    }

    /**
     * Применить фильтр
     */
    public void applyFilter() {
        setPage(1);
        clientsCount = -1;
        pagesCount = -1;
    }

    /**
     * Возвращает номер первой страницы, которую необходимо отрисовать в пэйджинаторе.
     *
     * @return номер первой страницы
     */
    private int getPageStart() {
        int pageStart = getPage() * getPageSize() - getPageSize();
        if (pageStart < 0) pageStart = 0;
        return pageStart;
    }

    /**
     * Возвращает номер последней страницы, которую необходимо отрисовать в пэйджинаторе
     *
     * @return номер последней страницы
     */
    private int getPageEnd() {
        int pageEnd = getPageStart() + getPageSize();
        if (pageEnd > getClientsCount()) pageEnd = getClientsCount();
        return pageEnd;
    }

    public List<Client> getClients() {
        //  Получаем пользователей
        List<User> users = getSessionBean().getGoodfil().getUsers();

        //  Получаем клиентские группы
        List<ClientGroup> clientGroups = getSessionBean().getGoodfil().getClientGroups();

        List<Client> clients = gf().getClients(getPageStart(), getPageSize(), getSessionBean().getClientsFilter());

        //  Назначаем клиентам зависимости
        for (Client c : clients) {
            //  Назначаем клиентскую группу
//            for (ClientGroup clientGroup : clientGroups)
//                if (c.getClientGroupId() == clientGroup.getId())
//                    c.setClientGroup(clientGroup);

            //  Назначаем менеджера
            if (c.getManagerId() != null)
                for (User user : users)
                    if (user.getUserRoleId() == Role.MANAGER)
                        if (user.getId() == c.getManagerId())
                            c.setManager(user);

            //  Подсчитываем число заказов данного клиента
            //  UNSAFE: Небезопасное приведение к int
            c.setOrdersCount((int) getSessionBean().getGoodfil().getOrdersCountByClientId(c.getId()));

            //  Назначаем пользователя
            for (User user : users)
                if (user.getClientId() != null && user.getClientId() == c.getId())
                    c.setUser(user);
        }
        return clients;
    }

    /**
     * Возвращает список клиентов.
     *
     * @return список клиентов
     */
    public List<SelectItem> getClientsAsSelectItems() {
        List<SelectItem> result = new ArrayList<SelectItem>();
        result.add(new SelectItem(-1, "Не выбран"));
        for (Client c : getClients())
            result.add(new SelectItem(c.getId(), c.getCompanyName()));
        return result;
    }

    /**
     * Возвращает список клиентов без пользователей
     *
     * @return список клиентов
     */
    public List<SelectItem> getClientsWithoutUsersAsSelectItems() {
//        List<User> clientUsers = gf().getUsersByRoleId(Role.CLIENT);

        List<SelectItem> result = new ArrayList<SelectItem>();
        result.add(new SelectItem(-1, "Не выбран"));
        for (Client c : gf().getClients()) {
//            boolean b = false;
//            for (User user : clientUsers)
//                if (user.getClientId() != null && user.getClientId().longValue() == c.getId())
//                    b = true;
//
//            if (!b) result.add(new SelectItem(c.getId(), c.getCompanyName()));
            result.add(new SelectItem(c.getId(), c.getCompanyName()));
        }

        return result;
    }

    private long clientId;

    public long getClientId() {
        return clientId;
    }

    public void setClientId(long clientId) {
        this.clientId = clientId;
    }

    /**
     * Удалить пользователя.
     */
    public void removeClient() {
        if (hasFacesErrors()) return;

        try {
            try {
                ClientUIEvent event = prepareClientUIEvent(Crud.DELETE);
                gf().removeClient(clientId);
                getAuditService().logClientUIEvent(event);
                facesInfo("Клиент удален");
            } catch (RemoveFailureException ex) {
                logger.error(ex);
                ex.printStackTrace();
                String[] objs = ex.getRemoveCheckResult().getLinkedObjects();
                for (String obj : objs) {
                    facesError("Клиента нельзя удалить, т.к. он связан с другими объектами.");
                    break;
                }
            }
        } catch (Exception e) {
            logger.error(e);
            e.printStackTrace();
            facesError("Ошибка удаления клиента");
        }
    }

    private ClientUIEvent prepareClientUIEvent(Crud crud) {
        Client client = gf().getClientById(clientId);

        String managerFio = null;
        if (client.getManagerId() != null) {
            User manager = gf().getUserById(client.getManagerId());
            if (manager != null) {
                managerFio = manager.getFio();
            }
        }

        ClientUIEvent event = new ClientUIEvent();
        event.setIp(getAuditHelper().getIp());
        event.setLogin(getAuditHelper().getLogin());
        event.setCrud(crud);
        event.setClientId(String.valueOf(client.getId()));
        event.setName(client.getCompanyName());
        event.setC1Num(client.getC1ClientNum());
        event.setManagerName(managerFio);
        event.setDebtBank(String.valueOf(client.getDebtBank()));
        event.setDebtCash(String.valueOf(client.getDebtCash()));

        return event;
    }

    public void blockRecovery(){
        gf().blockRecovery();
    }

    public List<SelectItem> getClientStateList(){
        List<SelectItem> list = new ArrayList<SelectItem>();
        list.add(new SelectItem(-1, "Не выбрано"));
        for (Pair pair : ClientState.list()) {
            list.add(new SelectItem(pair.getId(), pair.getValue()));
        }
        return list;
    }
}
